﻿using DotNetCommon.Data;
using DotNetCommon.Extensions;
using DotNetCommon.Logger;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading;

namespace DotNetCommon
{
    /// <summary>
    /// Roslyn编译器帮助类
    /// </summary>
    internal class RoslynHelper
    {
        /// <summary>
        /// 动态编译
        /// </summary>
        /// <param name="code">需要动态编译的代码</param>
        /// <returns>动态生成的程序集</returns>
        public static Result<Assembly> GenerateAssemblyFromCode(string code)
        {
            Assembly assembly = null;
            // 丛代码中转换表达式树
            SyntaxTree syntaxTree = CSharpSyntaxTree.ParseText(code);
            // 随机程序集名称
            string assemblyName = DateTime.Now.ToFileNameGuidString(".dll");
            // 引用
            var references = AppDomain.CurrentDomain.GetAssemblies()
                .Where(x => !x.IsDynamic && x.Location.IsNotNullOrEmptyOrWhiteSpace())
                .Select(x => MetadataReference.CreateFromFile(x.Location));

            // 创建编译对象
            CSharpCompilation compilation = CSharpCompilation.Create(assemblyName, new[] { syntaxTree }, references, new CSharpCompilationOptions(OutputKind.DynamicallyLinkedLibrary));

            using (var ms = new MemoryStream())
            {
                // 将编译好的IL代码放入内存流
                EmitResult result = compilation.Emit(ms);

                // 编译失败，提示
                if (!result.Success)
                {
                    var sb = new StringBuilder();
                    IEnumerable<Diagnostic> failures = result.Diagnostics.Where(diagnostic =>
                                diagnostic.IsWarningAsError ||
                                diagnostic.Severity == DiagnosticSeverity.Error);
                    foreach (Diagnostic diagnostic in failures)
                    {
                        sb.AppendLine($"{diagnostic.Id}: {diagnostic.GetMessage()}");
                    }
                    return Result.NotOk(sb.ToString());
                }
                else
                {
                    // 编译成功，从内存中加载编译好的程序集
                    ms.Seek(0, SeekOrigin.Begin);
                    var arr = ms.ToArray();
                    assembly = Assembly.Load(arr);
                    return Result.Ok(assembly);
                }
            }
        }
    }
}
